/** @addtogroup MMPF_USB
@{
*/

//#define exUSBPUB
#include "includes_fw.h"
#include "lib_retina.h"
#include "config_fw.h"
#include "mmpf_usbdescr.h"
#include "mmpf_usbvend.h"
#include "mmpf_usbextrn.h"

#include "mmp_lib.h" // for u_short/u_char/...
//#include "mmpf_usbmtp.h"
//#include "mmpf_usbdps.h"
//#include "mmpf_usbmsdc.h"
#include "mmpf_usbuac.h"
#include "mmpf_usbuvc.h"
#include "mmpf_spi.h"
#include "mmp_reg_usb.h"
#if (SUPPORT_PCCAM_FUNC==1)
#include "mmpf_usbpccam.h"
#define exUSBPCSYNC
#if SUPPORT_PCSYNC_FUNC == 1
#include "mmpf_usbpcsyn.h"
#endif
#undef  exUSBPCSYNC

extern  MMP_ULONG   glMSDCStatusBufAddr, glMSDCInterfaceBufAddr;
extern  MMP_ULONG   glPccamPrvResolution;

#endif /* (SUPPORT_PCCAM_FUNC==1) */

#include "customer.h"

MMP_ULONG   glUsbMaxPacketSize;
MMP_ULONG   glMSDCTxBufAddr;
MMP_ULONG   glMSDCRxBufAddr;
MMP_ULONG   glMSDCCmdBufAddr;
MMP_ULONG   glMSDCHandshackBufAddr, glMSDCStatusBufAddr;
MMP_ULONG   glMSDCInterfaceBufAddr, glMSDCInterfaceBufSize;

//MMP_ULONG   glMSDCBufStarAddr;
//MMP_ULONG   glUsbCtlBufStarAddr;

extern MMP_UBYTE gbSwitchSensor;

#if SUPPORT_UVC_FUNC == 0
extern MMP_UBYTE USB_PRODUCT_STR[14];
extern MMP_ULONG   glUsbOperationSpeed;
#endif

#if SUPPORT_MSDC_FUNC
extern  MMP_UBYTE   MSDC_DEVICE_DESCRIPTOR[];
extern  MMP_UBYTE   MSDC_DEVICE_QUALIFIER_DESCRIPTOR[];

extern  MMP_UBYTE   MSDC_OTHER_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_UBYTE   MSDC_FULL_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_UBYTE   MSDC_HIGH_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_ULONG   glMSDCInterfaceBufSize;
#endif

#if SUPPORT_PCCAM_FUNC
extern  MMP_UBYTE   PCCAM_DEVICE_DESCRIPTOR[];
extern  MMP_UBYTE   PCCAM_FULL_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_UBYTE   PCCAM_HIGH_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_UBYTE   PCCAM_OTHER_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_UBYTE   PCCAM_DEVICE_QUALIFIER_DESCRIPTOR[];
#endif

#if SUPPORT_MTP_FUNC
extern  MMP_UBYTE   MTP_DEVICE_DESCRIPTOR[];
extern  MMP_UBYTE   MTP_DEVICE_QUALIFIER_DESCRIPTOR[];
extern  MMP_UBYTE   MTP_OTHER_SPEED_CONFIG_DESCRIPTOR[0x27];
extern  MMP_UBYTE   MTP_FULL_SPEED_CONFIG_DESCRIPTOR[0x27];
extern  MMP_UBYTE   MTP_HIGH_SPEED_CONFIG_DESCRIPTOR[0x27];
#endif

#if SUPPORT_PCSYNC_FUNC
extern  MMP_UBYTE   PCSYNC_DEVICE_DESCRIPTOR[];
extern  MMP_UBYTE   PCSYNC_FULL_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_UBYTE   PCSYNC_HIGH_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_UBYTE   PCSYNC_OTHER_SPEED_CONFIG_DESCRIPTOR[0x20];
extern  MMP_UBYTE   PCSYNC_DEVICE_QUALIFIER_DESCRIPTOR[];
#endif

extern USB_DESCRIPTOR      UsbDescriptorInfo;
#if SUPPORT_MSDC_FUNC
extern MMP_ULONG   glUsbMSDCState;
extern MMP_ULONG   glMSDCRxBufOffset;
#endif

#if (SUPPORT_UVC_FUNC==1)
#include "mmpf_usbvend.h"

#if USE_SIMPLIFIED_DESC == 0
MMP_UBYTE USBDescBufAddr[0x800];
#endif
extern  MMP_UBYTE gbUsbHighSpeed;
extern  MMP_UBYTE  USBOutData;
MMP_USHORT   UVCTxFIFOSize;//EP2TxFIFOSize;
#endif

#if (SUPPORT_MTP_FUNC==1)||(SUPPORT_DPS_FUNC==1)
extern  MMP_UBYTE   MtpInitInMainON;//brian060831
extern  MMP_UBYTE   gflag_SessionOpened;//brian060831

//extern    void    MTPInit(MTP_DMA_HANDLE BufHandle);
extern MTP_DMA_HANDLE   MTPBufHandle;
#endif

#if (UVC_SETTING_LOAD_FROM_FLASH)
extern MMP_UBYTE Customer_Table_Setting[];
extern MMP_USHORT  gsSNSTRING_HEAD_OFFSET;
#endif

#if defined(USB_FW)||(USB_EN)

#pragma O0


#if (USB_PHY_TEST_MODE_EN == 1)
	MMP_UBYTE spi_read[]=
	{
		// read 20, 0a, 2001                        
		0x01,	// CS_N = 1  
		0x00,                                                 
		0x02,	// device addr bit0                   
		0x00,	                                     
		0x02,   //	bit1
		0x04,                                        
		0x06,	// bit2                               
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                                                               
		0x04,
		0x06,
		        // reg_addr = 0a                                       
		0x00,	                                     
		0x02,	// reg_addr bit0                      
		0x00,	                                     
		0x02,	// bit 1                              
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02, 
		0x00,
		0x02,                                       

		0x00,	                                     
		0x02,	// data0  bit0   
		//
		//read A013[0]
		0x00,	                                     
		0x02,	// bit 1                              
		//read A013[0]
		0x00,                                        
		0x02,         
		//read A013[0]                               
		0x00,                                        
		0x02,                                        
		//read A013[0]                               
		0x04,                                        
		0x06,                                        
		//read A013[0]                               
		0x04,                                        
		0x06,                                        
		//read A013[0]                               
		0x00,                                        
		0x02,
		//read A013[0]                               
		0x04,
		0x06,                                        
		//read A013[0]                               

		0x04,	                                     
		0x06,	// data1  bit0                        
		//read A013[0]                               
		0x04,	                                     
		0x06,	// bit 1                              
		//read A013[0]                               
		0x04,                                        
		0x06,                                        
		//read A013[0]                               
		0x04,                                        
		0x06,                                        
		//read A013[0]                               
		0x04,                                        
		0x06,                                        
		//read A013[0]                               
		0x04,                                        
		0x06,
		//read A013[0]                               
		0x04,
		0x06,                                        
		//read A013[0]                               
		0x04,                                        
		0x06,                                        
		//read A013[0]                               

		0x00,
		0x00,                                        
		0x01,	// CS_N =1                            

	};


	MMP_UBYTE spi_write[]=
	{
		// set 20, 0A, 2001                          
		0x01,	// CS_N = 1   
		0x00,                        
		0x02,	// device addr bit0                   
		0x00,	                                     
		0x02,   //	bit1                         
		0x04,                                        
		0x06,	// bit2                                
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		                                           
		0x00,	                                     
		0x02,	// reg_addr bit0                      
		0x00,	                                     
		0x02,	// bit 1                              
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02, 
		0x00,
		0x02,                                       


		0x00,	                                     
		0x02,	// data0  bit0   
		0x00,	                                     
		0x02,	// bit 1                              
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,
		0x00,                                        
		0x02,                                       
		0x00,                                        
		0x02,
		0x00,                                        
		0x02,                                       

		0x00,	                                     
		0x02,	// data0  bit0   
		0x00,	                                     
		0x02,	// bit 1                              
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,                                        
		0x00,                                        
		0x02,
		0x00,
		0x02,                                        


		0x00,
		0x00,                                        
		0x01,	// CS_N =1                            

	};


void SPI_Read(MMP_UBYTE addr)
{
	AITPS_USB_DMA pUSB_DMA = AITC_BASE_USBDMA;
    MMP_ULONG i;
    MMP_UBYTE bit;
    MMP_UBYTE spi_array[sizeof(spi_read)];

  //  AITPS_GBL   pGBL = AITC_BASE_GBL;
//    if(pGBL->GBL_CHIP_ECO > 0 ) {
//        return ;
//    }

    RTNA_DBG_Byte(0, addr);
    RTNA_DBG_Str(0, " output = ");  

    for (i=0; i<sizeof(spi_read); i++)
         spi_array[i] = spi_read[i];


    for(i=0; i<8; i++)
    {
        if(addr&(1<<i)){
            bit = 17 + (7-i)*2 ;
            spi_array[bit] = 0x04;
            spi_array[bit+1] = 0x06;
        }                
    }

    
    
    for (i=0; i<sizeof(spi_read); i++) {
        
        //*(volatile MMP_UBYTE *)0x80006012 = spi_array[i];
         pUSB_DMA->USB_PHY_SPI_CTL1 = spi_array[i];
        //A810H_WriteI2CRegW(0x8c10, spi_2[i] << 5);
        if((i >= 34) && (i%2 == 0))
        {
            if(pUSB_DMA->USB_PHY_SPI_CTL2)
                RTNA_DBG_Str(0, "1");
            else
                RTNA_DBG_Str(0, "0");
        }
    }
    RTNA_DBG_Str(0, "\r\n");  
}


void SPI_Write(MMP_UBYTE addr, MMP_USHORT data)
{
	AITPS_USB_DMA pUSB_DMA = AITC_BASE_USBDMA;
    MMP_ULONG i;
    MMP_UBYTE bit;
    MMP_UBYTE spi_array[sizeof(spi_write)];
 //   AITPS_GBL   pGBL = AITC_BASE_GBL;
//    if(pGBL->GBL_CHIP_ECO > 0 ) {
//        return ;
//    }

#if 0
    RTNA_DBG_Byte(0, addr);
    RTNA_DBG_Str(0, " input = ");  
    RTNA_DBG_Short(0, data);
    RTNA_DBG_Str(0, "\r\n");
#endif

    for (i=0; i<sizeof(spi_write); i++)
         spi_array[i] = spi_write[i];


    for(i=0; i<8; i++)
    {
        if(addr&(1<<i)){
            bit = 17 + (7-i)*2 ;
            spi_array[bit] = 0x04;
            spi_array[bit+1] = 0x06;
        }                
    }

    for(i=0; i<16; i++)
    {
        if(data&(1<<i)){
            bit = 33 + (15-i)*2 ;
            spi_array[bit] = 0x04;
            spi_array[bit+1] = 0x06;
        }                
    }    
    
    for (i=0; i<sizeof(spi_write); i++) {
        
        pUSB_DMA->USB_PHY_SPI_CTL1 = spi_array[i];
        //A810H_WriteI2CRegW(0x8c10, spi_2[i] << 5);
    }
    //RTNA_DBG_Str(0, "\r\n");  
}

#endif //(USB_PHY_TEST_MODE_EN == 1)

#if (SUPPORT_UVC_FUNC == 0x1)
//*********************************************************************
// function : usb_desc_init
// input    : none
// output   : none
//*********************************************************************
void usb_desc_init(void)
{
#if USE_SIMPLIFIED_DESC == 0
    u_short i;

    for(i = 0;i < (DEVICE_DESCRIPTOR_DATA1_ADDR - DEVICE_QUALIFIER_DESCRIPTOR_DATA1_ADDR);i++) {
        USBDescBufAddr[DEVICE_QUALIFIER_DESCRIPTOR_DATA1_ADDR + i] = DEVICE_QUALIFIER_DESCRIPTOR_DATA1[i];
    }        
    for(i = 0;i < (CONFIG_DESCRIPTOR_DATA1_ADDR - DEVICE_DESCRIPTOR_DATA1_ADDR);i++) {
        USBDescBufAddr[DEVICE_DESCRIPTOR_DATA1_ADDR + i] = DEVICE_DESCRIPTOR_DATA1[i];
    }
    for(i = 0;i < (LANGUAGE_ID_DATA_ADDR - CONFIG_DESCRIPTOR_DATA1_ADDR);i++) {
        if(gbUsbHighSpeed) {
#if SUPPORT_SWITCH_CAMERA
            if(gbSwitchSensor==MAIN_SENSOR) {
                USBDescBufAddr[CONFIG_DESCRIPTOR_DATA1_ADDR + i] = HS_CONFIG_DESCRIPTOR_DATA1[i];
            } else {
                USBDescBufAddr[CONFIG_DESCRIPTOR_DATA1_ADDR + i] = HS_CONFIG_DESCRIPTOR_DATA2[i];
            }
#else
            USBDescBufAddr[CONFIG_DESCRIPTOR_DATA1_ADDR + i] = HS_CONFIG_DESCRIPTOR_DATA1[i];
#endif
        } else {
            USBDescBufAddr[CONFIG_DESCRIPTOR_DATA1_ADDR + i] = CONFIG_DESCRIPTOR_DATA1[i];
        }
    }

#if 0    

    for(i = 0;i < (LANGUAGE_ID_DATA[0]);i++) {
        USBDescBufAddr[LANGUAGE_ID_DATA_ADDR + i] = LANGUAGE_ID_DATA[i];
    }
    for(i = 0;i < (MANUFACTURER_STRING_DATA[0]);i++) {
        USBDescBufAddr[MANUFACTURER_STRING_DATA_ADDR + i] = MANUFACTURER_STRING_DATA[i];
    }
    for(i = 0;i < (PRODUCT_STRING_DATA[0]);i++) {
        USBDescBufAddr[PRODUCT_STRING_DATA_ADDR + i] = PRODUCT_STRING_DATA[i];
    }   
    for(i = 0;i < (SERIALNUMBER_STRING_DATA[0]);i++) {
        USBDescBufAddr[SERIALNUMBER_STRING_DATA_ADDR + i] = SERIALNUMBER_STRING_DATA[i];
    }

#else

    // USB language ID buffer initialize
    UsbDescriptorInfo.pStrDescriptor0 = LANGUAGE_ID_DATA;
#if SUPPORT_SWITCH_CAMERA
    if(gbSwitchSensor==MAIN_SENSOR) {
        UsbDescriptorInfo.StrDescriptor0Offset = LANGUAGE_ID_DATA_ADDR1;
    } else {
        UsbDescriptorInfo.StrDescriptor0Offset = LANGUAGE_ID_DATA_ADDR2;
    }
#else
    UsbDescriptorInfo.StrDescriptor0Offset = LANGUAGE_ID_DATA_ADDR;
#endif
    //dbg_printf(3, "string0 size = 0x%x, offset is 0x%x\r\n", UsbDescriptorInfo.pStrDescriptor0[0], UsbDescriptorInfo.StrDescriptor0Offset);
    for(i = 0;i < (UsbDescriptorInfo.pStrDescriptor0[0]);i++) {
        USBDescBufAddr[UsbDescriptorInfo.StrDescriptor0Offset + i] = UsbDescriptorInfo.pStrDescriptor0[i];
    }

#if (CUSTOMER == LON)
    // USB manufacturer string buffer initialize
    #if (UVC_SETTING_LOAD_FROM_FLASH)
        if( (Customer_Table_Setting[CUSTOMER_INIT_DATA_HEAD_OFFSET] == CUSTOMER_INIT_DATA_TAG) &&
          (Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET] == CUSTOMER_INIT_DATA_TAG)           &&
          (((((MMP_USHORT)Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+2]) << 8)|((MMP_USHORT)Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+3])) != 0xFFFF) &&
          (Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+4] > 2) )
        {
            UsbDescriptorInfo.pStrDescriptor1 = &Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+4];
            UsbDescriptorInfo.StrDescriptor1Offset = UsbDescriptorInfo.StrDescriptor0Offset + UsbDescriptorInfo.pStrDescriptor0[0];
            //dbg_printf(3, "string1 size = 0x%x, offset is 0x%x\r\n", UsbDescriptorInfo.pStrDescriptor1[0], UsbDescriptorInfo.StrDescriptor1Offset);
            for(i = 0;i < (UsbDescriptorInfo.pStrDescriptor1[0]);i++) {
                USBDescBufAddr[UsbDescriptorInfo.StrDescriptor1Offset + i] = UsbDescriptorInfo.pStrDescriptor1[i];
            }
        }
        else
    #endif
        {
            UsbDescriptorInfo.pStrDescriptor1 = MANUFACTURER_STRING_DATA;
            UsbDescriptorInfo.StrDescriptor1Offset = UsbDescriptorInfo.StrDescriptor0Offset + UsbDescriptorInfo.pStrDescriptor0[0];
            //dbg_printf(3, "string1 size = 0x%x, offset is 0x%x\r\n", UsbDescriptorInfo.pStrDescriptor1[0], UsbDescriptorInfo.StrDescriptor1Offset);
            for(i = 0;i < (UsbDescriptorInfo.pStrDescriptor1[0]);i++) {
                USBDescBufAddr[UsbDescriptorInfo.StrDescriptor1Offset + i] = UsbDescriptorInfo.pStrDescriptor1[i];
            }
        }
#else
    // USB manufacturer string buffer initialize
    UsbDescriptorInfo.pStrDescriptor1 = MANUFACTURER_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor1Offset = UsbDescriptorInfo.StrDescriptor0Offset + UsbDescriptorInfo.pStrDescriptor0[0];
    for(i = 0;i < (UsbDescriptorInfo.pStrDescriptor1[0]);i++) {
        USBDescBufAddr[UsbDescriptorInfo.StrDescriptor1Offset + i] = UsbDescriptorInfo.pStrDescriptor1[i];
    }
#endif

    // USB product string buffer initialize
    UsbDescriptorInfo.pStrDescriptor2 = PRODUCT_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor2Offset = UsbDescriptorInfo.StrDescriptor1Offset + UsbDescriptorInfo.pStrDescriptor1[0];
    //dbg_printf(3, "string2 size = 0x%x, offset is 0x%x\r\n", UsbDescriptorInfo.pStrDescriptor2[0], UsbDescriptorInfo.StrDescriptor2Offset);
    for(i = 0;i < (UsbDescriptorInfo.pStrDescriptor2[0]);i++) {
        USBDescBufAddr[UsbDescriptorInfo.StrDescriptor2Offset + i] = UsbDescriptorInfo.pStrDescriptor2[i];
    }   
    
#if (CUSTOMER == LIT)
    // USB serial number string buffer initialize
    UsbDescriptorInfo.pStrDescriptor3 = SERIALNUMBER_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor3Offset = UsbDescriptorInfo.StrDescriptor2Offset + UsbDescriptorInfo.pStrDescriptor2[0];

    for(i = 0;i < 2;i++) {
        USBDescBufAddr[UsbDescriptorInfo.StrDescriptor3Offset + i] = UsbDescriptorInfo.pStrDescriptor3[i];
    }
    for(i = 2;i < UsbDescriptorInfo.pStrDescriptor3[0];i++) {
        USBDescBufAddr[UsbDescriptorInfo.StrDescriptor3Offset + i] = gbFwBuildDate[i];
    }
#else
    // USB serial number string buffer initialize
    UsbDescriptorInfo.pStrDescriptor3 = SERIALNUMBER_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor3Offset = UsbDescriptorInfo.StrDescriptor2Offset + UsbDescriptorInfo.pStrDescriptor2[0];
    //dbg_printf(3, "string3 size = 0x%x, offset is 0x%x\r\n", UsbDescriptorInfo.pStrDescriptor3[0], UsbDescriptorInfo.StrDescriptor3Offset);
    for(i = 0;i < (UsbDescriptorInfo.pStrDescriptor3[0]);i++) {
        USBDescBufAddr[UsbDescriptorInfo.StrDescriptor3Offset + i] = UsbDescriptorInfo.pStrDescriptor3[i];
    }
#endif


#endif
#else

#if (CUSTOMER == ASU)&&(UVC_SETTING_LOAD_FROM_FLASH)
    MMP_USHORT i;
    // USB manufacturer string buffer initialize
    if( (Customer_Table_Setting[CUSTOMER_INIT_DATA_HEAD_OFFSET] == CUSTOMER_INIT_DATA_TAG) &&
      (Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET] == CUSTOMER_INIT_DATA_TAG)           &&
      (((((MMP_USHORT)Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+2]) << 8)|((MMP_USHORT)Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+3])) != 0xFFFF) &&
      (Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+4] > 2) )
    {
        MMP_UBYTE nStringLength;
        nStringLength = (MANUFACTURER_STRING_DATA[0]) < (Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+4]) ? (MANUFACTURER_STRING_DATA[0]): (Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+4]); //protect overwrite array
        for(i = 0;i < nStringLength;i++) {
            MANUFACTURER_STRING_DATA[i] = Customer_Table_Setting[gsSNSTRING_HEAD_OFFSET+4+i];
        }
    }
#endif
    
#endif
}                

void usb_ep_init(void)
{
    MMP_USHORT csr;      
    AITPS_USB_CTL pUSB_CTL = AITC_BASE_USBCTL;
#if 1
    pUSB_CTL->USB_POWER |= 0x20; // high speed enable
#else
    pUSB_CTL->USB_POWER &= ~0x20; // full speed enable
#endif
    if(pUSB_CTL->USB_POWER & HS_MODE_BIT) {
        gbUsbHighSpeed = 1; 
#if SUPPORT_UAC
        UsbWriteTxMaxP(PCCAM_AU_EP_ADDR, AU_EP_MAX_PK_SIZE_HS );
#endif
        UsbWriteTxMaxP(PCCAM_TX1_EP_ADDR, HS_TX_MAX_PK_SIZE);
#if USB_UVC_BULK_EP
        UVCTxFIFOSize = HS_TX_MAX_PK_SIZE;
#else
        UVCTxFIFOSize = HS_TX_MAX_PK_SIZE * TX_PER_FRAME ;
#endif       
        UsbWriteTxMaxP(PCCAM_EX_EP_ADDR, EX_EP_MAX_PK_SIZE );

#if SUPPORT_UAC
        csr = UsbReadTxEpCSR(PCCAM_AU_EP_ADDR);
        csr = csr & TXCSR_RW_MASK;
        UsbWriteTxEpCSR(PCCAM_AU_EP_ADDR, csr | SET_TX_ISO | SET_TX_MODE); // ISO 0x4000
#endif
        csr = UsbReadTxEpCSR(PCCAM_TX1_EP_ADDR);
        csr = csr & TXCSR_RW_MASK;

#if USB_UVC_BULK_EP
        UsbWriteTxEpCSR(PCCAM_TX1_EP_ADDR, csr | SET_TX_MODE ); // ISO 0x4000
#else        
        UsbWriteTxEpCSR(PCCAM_TX1_EP_ADDR, csr | SET_TX_MODE | SET_TX_ISO); // ISO 0x4000
#endif        
        csr = UsbReadTxEpCSR(PCCAM_EX_EP_ADDR);
        csr = csr & TXCSR_RW_MASK;
        UsbWriteTxEpCSR(PCCAM_EX_EP_ADDR, csr | SET_TX_MODE);

#if SUPPORT_HID_FUNC
        UsbWriteTxMaxP(HID_EP_ADDR, HID_MAX_PK_SIZE );
        csr = UsbReadTxEpCSR(HID_EP_ADDR);
        csr = csr & TXCSR_RW_MASK;
        UsbWriteTxEpCSR(HID_EP_ADDR, csr | SET_TX_MODE);
#endif
    } else {
        gbUsbHighSpeed = 0;
#if SUPPORT_UAC
        UsbWriteTxMaxP(PCCAM_AU_EP_ADDR, AU_EP_MAX_PK_SIZE_FS);
#endif
        UsbWriteTxMaxP(PCCAM_TX1_EP_ADDR, FS_TX_MAX_PK_SIZE);
        UVCTxFIFOSize = FS_TX_MAX_PK_SIZE ;
        UsbWriteTxMaxP(PCCAM_EX_EP_ADDR, EX_EP_MAX_PK_SIZE);

#if SUPPORT_UAC
        csr = UsbReadTxEpCSR(PCCAM_AU_EP_ADDR);
        csr = csr & TXCSR_RW_MASK;
        UsbWriteTxEpCSR(PCCAM_AU_EP_ADDR, csr | SET_TX_ISO | SET_TX_MODE); // ISO 0x4000
#endif
        csr = UsbReadTxEpCSR(PCCAM_TX1_EP_ADDR);
        csr = csr & TXCSR_RW_MASK;
#if USB_UVC_BULK_EP
        UsbWriteTxEpCSR(PCCAM_TX1_EP_ADDR, csr | SET_TX_MODE ); // ISO 0x4000
#else        
        UsbWriteTxEpCSR(PCCAM_TX1_EP_ADDR, csr | SET_TX_MODE | SET_TX_ISO); // ISO 0x4000
#endif        
        csr = UsbReadTxEpCSR(PCCAM_EX_EP_ADDR);
        csr = csr & TXCSR_RW_MASK;
        UsbWriteTxEpCSR(PCCAM_EX_EP_ADDR, csr | SET_TX_MODE);
    }
}

extern MMP_UBYTE gbEP0NotEnd;
//*********************************************************************
// function : A810L_InitUSB
// input    : none
// output   : none
//*********************************************************************
void A810L_InitUSB(void)
{
 	AITPS_USB_CTL pUSB_CTL = AITC_BASE_USBCTL;

    gbEP0NotEnd = 0;
    // varible initial
    USBOutData = 0;
    USBInPhase = 0;
    USBOutPhase = 0;
#if SUPPORT_SWITCH_CAMERA
    USBConfig1Len = ((gbSwitchSensor==MAIN_SENSOR)?CAMERA_1_CONFIG_DESCRIPTOR_LEN:CAMERA_2_CONFIG_DESCRIPTOR_LEN);
#else
    USBConfig1Len = CONFIG_DESCRIPTOR_LEN;
#endif

    usb_ep_init();

    pUSB_CTL->USB_TX_INT_EN = EP0_INT_BIT /*| EP1_TX_INT_BIT | EP2_TX_INT_BIT*/;
    pUSB_CTL->USB_RX_INT_EN = 0;
//#ifdef UVC_TEST   
#ifdef ZDW_BARCODE_POWER_ON_WORKING
    pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT /*| SOF_INT_BIT | SUSPEND_INT_BIT*/ | RESUME_INT_BIT ;
#else
	pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT /*| SOF_INT_BIT*/ | SUSPEND_INT_BIT | RESUME_INT_BIT ;
#endif    
    
//#else
//    pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT /*| SUSPEND_INT_BIT*/;

//#endif

    usb_desc_init();

    USBAlterSetting = 0x00;

    USBConfig = 0x00;
    USBInterface = 0x00;
    USBEndpoint = 0x00;
    USBFrameNum = 0x00;
    USBDevice = 0x00;
    uvc_init(1);
#if SUPPORT_UAC
    uac_init();
#endif
    USBConfigDescLen = USBConfig1Len;
#if SUPPORT_HID_FUNC
    USBReportDescLen = REPORT_DESCRIPTOR_LEN;
#endif
#if (JTAG == 1)// V06 : force usb enum again if using ICE to debug
    //usb_sw_enum();
#endif
}
//*********************************************************************
// function : USB_GET_SOF_NUM
// input    : none
// output   : uSOF count
//*********************************************************************
MMP_ULONG USB_GET_SOF_NUM(void)
{
#if USB_SOF_REG_MODE
	//using register
    AITPS_USB_DMA pUSB_DMA = AITC_BASE_USBDMA;
    
    return pUSB_DMA->USB_SOF_CNT;
#else
	//using INT
    extern volatile MMP_ULONG SOFNUM;
    return SOFNUM;
#endif
}

//*********************************************************************
// function : usb_sw_enum
// input    : none
// output   : none
//*********************************************************************
//#if (JTAG == 1)
void usb_sw_enum(void)
{
    MMP_UBYTE tmp;
    AITPS_USB_CTL pUSB_CTL = AITC_BASE_USBCTL;


    pUSB_CTL->USB_POWER &= ~0x40;

    for(tmp = 0;tmp < 100;tmp++)
        ;

    pUSB_CTL->USB_POWER |= 0x40;
}
//#endif


#else // not UVC

//------------------------------------------------------------------------------
//  Function    : UsbMSDCModeReset
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
void UsbMSDCModeReset(void)
{
    AITPS_USB_CTL pUSB_CTL = AITC_BASE_USBCTL;
    MMP_ULONG i;

    MMPF_MSDC_Init();

#if USB_DMA_MODE
    pUSB_CTL->USB_TX_INT_EN = EP0_INT_BIT;
    pUSB_CTL->USB_RX_INT_EN = 0;
    pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT | SUSPEND_INT_BIT | RESUME_INT_BIT;
#else
    pUSB_CTL->USB_TX_INT_EN = EP0_INT_BIT | EP1_TX_INT_BIT;
#if(MSDC_RX_EP2 == 1)
    pUSB_CTL->USB_RX_INT_EN |= EP2_RX_INT_BIT;
#else // ep1
    pUSB_CTL->USB_RX_INT_EN = EP1_RX_INT_BIT;
#endif // diff end
    pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT | SUSPEND_INT_BIT | RESUME_INT_BIT;
#endif
    UsbWriteTxMaxP(MSDC_TX_EP_ADDR, 0x40);
    UsbWriteRxMaxP(MSDC_RX_EP_ADDR, 0x40);

    UsbDescriptorInfo.pDeviceDescriptor = MSDC_DEVICE_DESCRIPTOR;
    UsbDescriptorInfo.DeviceDescriptorSize = MSDC_DEVICE_DESCRIPTOR[0];
    UsbDescriptorInfo.pConfigDescriptor = MSDC_FULL_SPEED_CONFIG_DESCRIPTOR;
    UsbDescriptorInfo.ConfigDescriptorSize = sizeof(MSDC_FULL_SPEED_CONFIG_DESCRIPTOR);
    UsbDescriptorInfo.pStrDescriptor0 = LANGID_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor0Size = LANGID_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor1 = MANUFACTURER_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor1Size = MANUFACTURER_STRING_DATA[0];;

    for(i = 0;i < 14;i++)
        PRODUCT_STRING_DATA[2 * i + 2] = USB_PRODUCT_STR[i];

    UsbDescriptorInfo.pStrDescriptor2 = PRODUCT_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor2Size = PRODUCT_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor3 = SERIALNUMBER_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor3Size = SERIALNUMBER_STRING_DATA[0];;


    if(glUsbOperationSpeed == USB_HIGH_SPEED) {
        UsbWriteTxMaxP(MSDC_TX_EP_ADDR, 0x200);
        UsbWriteRxMaxP(MSDC_RX_EP_ADDR, 0x200);

        UsbDescriptorInfo.pOtherSpeedConfigDescriptor = MSDC_OTHER_SPEED_CONFIG_DESCRIPTOR;
        UsbDescriptorInfo.OtherSpeedConfigDescriptorSize = sizeof(MSDC_OTHER_SPEED_CONFIG_DESCRIPTOR);;
        UsbDescriptorInfo.pDeviceQualifierDescriptor = MSDC_DEVICE_QUALIFIER_DESCRIPTOR;
        UsbDescriptorInfo.DeviceQualifierDescriptorSize = MSDC_DEVICE_QUALIFIER_DESCRIPTOR[0];
        UsbDescriptorInfo.pConfigDescriptor = MSDC_HIGH_SPEED_CONFIG_DESCRIPTOR;
        UsbDescriptorInfo.ConfigDescriptorSize = sizeof(MSDC_HIGH_SPEED_CONFIG_DESCRIPTOR);
    }

	glCSWResidue = 0;
	gbCSWStatus = 0;
	gbIsStalled = MMP_FALSE;
	
    glUsbMSDCState = MSDC_CBW_STATE;
    glMSDCRxBufOffset = 0;
    MSDC_Reset_ReadyFlag();         //Ted update

	//UsbEndpointReset();
    MMPF_MSDC_TriggerUsbRX(glMSDCCmdBufAddr,0x1F);

}

#if (SUPPORT_PCCAM_FUNC==1)
//------------------------------------------------------------------------------
//  Function    : UsbPCCAMModeReset
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
void UsbPCCAMModeReset(void)
{
    AITPS_USB_CTL pUSB_CTL = AITC_BASE_USBCTL;
    MMP_ULONG i;

    //AITPS_USB_DMA pUSB_DMA = AITC_BASE_USBDMA;
    //pUSB_DMA->USB_OTG_CTL = 0x10;

    pUSB_CTL->USB_TX_INT_EN = EP0_INT_BIT;
    pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT;

    UsbWriteTxMaxP(PCCAM_TX1_EP_ADDR, 0x40);

    UsbDescriptorInfo.pDeviceDescriptor = PCCAM_DEVICE_DESCRIPTOR;
    UsbDescriptorInfo.DeviceDescriptorSize = PCCAM_DEVICE_DESCRIPTOR[0];
    UsbDescriptorInfo.pConfigDescriptor = PCCAM_FULL_SPEED_CONFIG_DESCRIPTOR;
    UsbDescriptorInfo.ConfigDescriptorSize = sizeof(PCCAM_FULL_SPEED_CONFIG_DESCRIPTOR);
    UsbDescriptorInfo.pStrDescriptor0 = LANGID_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor0Size = LANGID_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor1 = MANUFACTURER_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor1Size = MANUFACTURER_STRING_DATA[0];;

    for(i = 0;i < 14;i++)
        PRODUCT_STRING_DATA[2 * i + 2] = USB_PRODUCT_STR[i];

    UsbDescriptorInfo.pStrDescriptor2 = PRODUCT_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor2Size = PRODUCT_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor3 = FRAME1_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor3Size = FRAME1_STRING_DATA[0];;

    if(glUsbOperationSpeed == USB_HIGH_SPEED) {
        UsbWriteTxMaxP(PCCAM_TX1_EP_ADDR, 0x200);

        UsbDescriptorInfo.pOtherSpeedConfigDescriptor = PCCAM_OTHER_SPEED_CONFIG_DESCRIPTOR;
        UsbDescriptorInfo.OtherSpeedConfigDescriptorSize = sizeof(PCCAM_OTHER_SPEED_CONFIG_DESCRIPTOR);;
        UsbDescriptorInfo.pDeviceQualifierDescriptor = PCCAM_DEVICE_QUALIFIER_DESCRIPTOR;
        UsbDescriptorInfo.DeviceQualifierDescriptorSize = PCCAM_DEVICE_QUALIFIER_DESCRIPTOR[0];
        UsbDescriptorInfo.pConfigDescriptor = PCCAM_HIGH_SPEED_CONFIG_DESCRIPTOR;
        UsbDescriptorInfo.ConfigDescriptorSize = sizeof(PCCAM_HIGH_SPEED_CONFIG_DESCRIPTOR);;
    }

    //glPccamPrvResolution = PCCAM_RES_INVALID;
}
#endif /* (SUPPORT_PCCAM_FUNC==1) */

#if (SUPPORT_MTP_FUNC==1)
//------------------------------------------------------------------------------
//  Function    : UsbMSDCModeReset
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
void UsbMTPModeReset(void)
{
   	AITPS_USB_CTL pUSB_CTL = AITC_BASE_USBCTL;
    MMP_USHORT csr;

    MMPF_MTP_ResetDevice();

#if USB_DMA_MODE
    pUSB_CTL->USB_TX_INT_EN = EP0_INT_BIT;
    pUSB_CTL->USB_RX_INT_EN = 0;
    pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT;
#else
    pUSB_CTL->USB_TX_INT_EN = EP0_INT_BIT | EP1_TX_INT_BIT;
    pUSB_CTL->USB_RX_INT_EN = EP1_RX_INT_BIT;
    pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT;
#endif
    pUSB_CTL->USB_TX_INT_EN |= EP3_TX_INT_BIT;

    UsbWriteTxMaxP(MTP_TX_EP_ADDR, 0x40);
    UsbWriteRxMaxP(MTP_RX_EP_ADDR, 0x40);

    //=========Enable EP3    ============
    UsbWriteTxMaxP(MTP_INT_EP_ADDR, 0x40);
    csr = UsbReadTxEpCSR(MTP_INT_EP_ADDR);
    csr = csr & TXCSR_RW_MASK;
    UsbWriteTxEpCSR(MTP_INT_EP_ADDR, csr | SET_TX_MODE);
    //====================================

    UsbDescriptorInfo.pDeviceDescriptor = MTP_DEVICE_DESCRIPTOR;
    UsbDescriptorInfo.DeviceDescriptorSize = MTP_DEVICE_DESCRIPTOR[0];
    UsbDescriptorInfo.pConfigDescriptor = MTP_FULL_SPEED_CONFIG_DESCRIPTOR;
    UsbDescriptorInfo.ConfigDescriptorSize = sizeof(MTP_FULL_SPEED_CONFIG_DESCRIPTOR);
    UsbDescriptorInfo.pExtendedConfigData = EXTENDED_CONFIGURATION_DATA;
    UsbDescriptorInfo.pExtendedConfigDataSize = EXTENDED_CONFIGURATION_DATA[0];
    UsbDescriptorInfo.pStrDescriptor0 = LANGID_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor0Size = LANGID_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor1 = MANUFACTURER_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor1Size = MANUFACTURER_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor2 = PRODUCT_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor2Size = PRODUCT_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor3 = FRAME1_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor3Size = FRAME1_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor4 = OS_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor4Size = OS_STRING_DATA[0];;


    if(glUsbOperationSpeed == USB_HIGH_SPEED) {
        UsbWriteTxMaxP(MTP_TX_EP_ADDR, 0x200);
        UsbWriteRxMaxP(MTP_RX_EP_ADDR, 0x200);

        UsbDescriptorInfo.pOtherSpeedConfigDescriptor = MTP_OTHER_SPEED_CONFIG_DESCRIPTOR;
        UsbDescriptorInfo.OtherSpeedConfigDescriptorSize = sizeof(MTP_OTHER_SPEED_CONFIG_DESCRIPTOR);;
        UsbDescriptorInfo.pDeviceQualifierDescriptor = MTP_DEVICE_QUALIFIER_DESCRIPTOR;
        UsbDescriptorInfo.DeviceQualifierDescriptorSize = MTP_DEVICE_QUALIFIER_DESCRIPTOR[0];
        UsbDescriptorInfo.pConfigDescriptor = MTP_HIGH_SPEED_CONFIG_DESCRIPTOR;
        UsbDescriptorInfo.ConfigDescriptorSize = sizeof(MTP_HIGH_SPEED_CONFIG_DESCRIPTOR);
    }

    glUsbMSDCState = MSDC_CBW_STATE;
    glMSDCRxBufOffset = 0;


    if(glUsbOperationSpeed == USB_HIGH_SPEED) {
        glUsbMaxPacketSize = 0x200;
    } else {
        glUsbMaxPacketSize = 0x40;
    }

    //MtpResetState();

}
#endif//#if (SUPPORT_MTP_FUNC==1)

//------------------------------------------------------------------------------
//  Function    : UsbPCSYNCModeReset
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
void UsbPCSYNCModeReset(void)
{
    AITPS_USB_CTL pUSB_CTL = AITC_BASE_USBCTL;

    pUSB_CTL->USB_TX_INT_EN = EP0_INT_BIT | EP1_TX_INT_BIT;
    pUSB_CTL->USB_RX_INT_EN = 0;
    pUSB_CTL->USB_INT_EVENT_EN = RESET_INT_BIT;

    UsbWriteTxMaxP(PCCAM_TX1_EP_ADDR, 0x40);

    UsbDescriptorInfo.pDeviceDescriptor = PCSYNC_DEVICE_DESCRIPTOR;
    UsbDescriptorInfo.DeviceDescriptorSize = PCSYNC_DEVICE_DESCRIPTOR[0];
    UsbDescriptorInfo.pConfigDescriptor = PCSYNC_FULL_SPEED_CONFIG_DESCRIPTOR;
    UsbDescriptorInfo.ConfigDescriptorSize = sizeof(PCSYNC_FULL_SPEED_CONFIG_DESCRIPTOR);
    UsbDescriptorInfo.pStrDescriptor0 = LANGID_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor0Size = LANGID_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor1 = MANUFACTURER_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor1Size = MANUFACTURER_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor2 = PRODUCT_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor2Size = PRODUCT_STRING_DATA[0];;
    UsbDescriptorInfo.pStrDescriptor3 = FRAME1_STRING_DATA;
    UsbDescriptorInfo.StrDescriptor3Size = FRAME1_STRING_DATA[0];;

    if(glUsbOperationSpeed == USB_HIGH_SPEED) {
        UsbWriteTxMaxP(PCCAM_TX1_EP_ADDR, 0x200);

        UsbDescriptorInfo.pOtherSpeedConfigDescriptor = PCSYNC_OTHER_SPEED_CONFIG_DESCRIPTOR;
        UsbDescriptorInfo.OtherSpeedConfigDescriptorSize = sizeof(PCSYNC_OTHER_SPEED_CONFIG_DESCRIPTOR);;
        UsbDescriptorInfo.pDeviceQualifierDescriptor = PCSYNC_DEVICE_QUALIFIER_DESCRIPTOR;
        UsbDescriptorInfo.DeviceQualifierDescriptorSize = PCSYNC_DEVICE_QUALIFIER_DESCRIPTOR[0];
        UsbDescriptorInfo.pConfigDescriptor = PCSYNC_HIGH_SPEED_CONFIG_DESCRIPTOR;
        UsbDescriptorInfo.ConfigDescriptorSize = sizeof(PCSYNC_HIGH_SPEED_CONFIG_DESCRIPTOR);;
    }
}
#endif


#endif  //#if   defined(USB_FW)
//#undef  exUSBPUB
/// @}
